package com.songyang.yougnsql.server.serialize;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.songyang.yougnsql.server.serialize.inter.YoungSqlSerialize;
import com.songyang.yougnsql.server.transport.YoungSQLDataPackage;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * @ClassName KryoUtils
 * @Description 序列化工具类
 * @date 2022/12/30 11:01
 * @Author yanceysong
 * @Version 1.0
 */
public class KryoEncoder implements YoungSqlSerialize {
    protected KryoEncoder() {
    }

    /**
     * 获取kryo的单例
     *
     * @return kryo对象
     */
    private static Kryo getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    /**
     * 序列化传输对象
     *
     * @param p 待序列化的对象
     * @return 反序列化的字节码
     */
    public byte[] serialize(YoungSQLDataPackage p) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        Output output = new Output(bos);
        getInstance().writeObject(output, p);//写入null时会报错
        output.close();
        return bos.toByteArray();
    }

    /**
     * 反序列化传输对象
     *
     * @param bytes 反序列化字节码
     * @return 传输对象
     */
    public YoungSQLDataPackage deserialize(byte[] bytes) {
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        Input input = new Input(bis);
        YoungSQLDataPackage p = KryoEncoder.getInstance().readObject(input, YoungSQLDataPackage.class);//读出null时会报错
        input.close();
        return p;
    }

    private enum Singleton {
        INSTANCE;
        private final Kryo singleton;

        //JVM会保证此方法绝对只调用一次
        Singleton() {
            singleton = new Kryo();
            // 如果没有多层次的对象引用相互引用，设为false，提高性能
            singleton.setReferences(false);
            // 注册序列化/反序列化的类
            singleton.register(YoungSQLDataPackage.class);
        }

        public Kryo getInstance() {
            return singleton;
        }
    }

//    public static void main(String[] args) {
//        YoungSQLDataPackage youngSQLDataPackage = new YoungSQLDataPackage("songyang", null);
//        byte[] bytes = KryoUtils.serialize(youngSQLDataPackage);
//        System.out.println("KryoUtils.deserialize(bytes).getData() = " + KryoUtils.deserialize(bytes).getData());
//    }
}
